package org.jsola.hr.service.impl;

import org.jsola.common.PageKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.ExcelKit;
import org.jsola.hr.common.GenerateExcelHead;
import org.jsola.hr.constant.FieldType;
import org.jsola.hr.constant.FormGroupModuleCode;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.ITreatmentDisposeTemplateDAO;
import org.jsola.hr.dto.*;
import org.jsola.hr.dto.excel.ExcelAxisDTO;
import org.jsola.hr.entity.FormGroupDO;
import org.jsola.hr.entity.FormGroupFieldDO;
import org.jsola.hr.entity.TreatmentDisposeEventDO;
import org.jsola.hr.entity.TreatmentDisposeTemplateDO;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.query.FormGroupFieldQuery;
import org.jsola.hr.query.TreatmentDisposeTemplateQuery;
import org.jsola.hr.service.IFormGroupFieldService;
import org.jsola.hr.service.IFormGroupService;
import org.jsola.hr.service.ITreatmentDisposeEventService;
import org.jsola.hr.service.ITreatmentDisposeTemplateService;
import org.jsola.hr.vo.FormGroupFieldVO;
import org.jsola.hr.vo.FormGroupVO;
import org.jsola.hr.vo.TreatmentDisposeTemplateListVO;
import org.jsola.hr.vo.TreatmentDisposeTemplateVO;
import org.jsola.user.core.TokenUser;
import org.jsola.user.entity.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 待遇处理模板
 *
 * @author zhr
 */
@Service("hrTreatmentDisposeTemplateServiceImpl")
public class TreatmentDisposeTemplateServiceImpl implements ITreatmentDisposeTemplateService {

    @Autowired
    private ITreatmentDisposeTemplateDAO treatmentDisposeTemplateDAO;

    @Autowired
    private IFormGroupFieldService formGroupFieldService;

    @Autowired
    private IFormGroupService formGroupService;

    @Autowired
    private IUserProviderService userProviderService;

    @Lazy
    @Autowired
    private ITreatmentDisposeEventService treatmentDisposeEventService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public TreatmentDisposeTemplateVO save(TreatmentDisposeTemplateAddDTO treatmentDisposeTemplateAddDTO, TokenUser tokenUser) {
        // 转DO
        TreatmentDisposeTemplateDO template = treatmentDisposeTemplateAddDTO.to(TreatmentDisposeTemplateDO.class);
        // 校验名称
        checkTemplateName(treatmentDisposeTemplateAddDTO.getTemplateName(), null, tokenUser);
        // 校验字段名称
        checkFieldName(treatmentDisposeTemplateAddDTO);
        // 保存
        template = save(template, tokenUser.getSiteId(), tokenUser.getUserId());
        // 拿到表单
        List<FormGroupAddDTO> formGroupList = treatmentDisposeTemplateAddDTO.getFormGroupAddList();
        // 校验字段名称全模板不可重复
        checkFieldName(formGroupList, null);
        // 这里表单需要单个保存后面需要用到保存后的表单Id
        Long processId = null;
        List<FormGroupDO> processChildList = new ArrayList<>();
        List<FormGroupFieldAddDTO> bachSaveFieldList = new ArrayList<>();
        long sort = 1;
        for (FormGroupAddDTO formGroupAdd : formGroupList) {
            // 拿到表单内的字段
            List<FormGroupFieldAddDTO> formGroupFieldAddList = formGroupAdd.getFormGroupFieldAddList();
            FormGroupDO formGroup = formGroupAdd.to(FormGroupDO.class);
            formGroup.setSort(sort++);
            formGroup.setLevel(1);
            formGroup.setSubjectId(template.getId());
            FormGroupDO saveFormGroup = formGroupService.save(formGroup, tokenUser.getSiteId(), tokenUser.getUserId());
            if (FormGroupModuleCode.PROCESS_CHILD.equals(formGroupAdd.getModuleCode())) {
                processChildList.add(saveFormGroup);
            }
            if (FormGroupModuleCode.PROCESS.equals(formGroupAdd.getModuleCode())) {
                processId = saveFormGroup.getId();
            }
            if (!CollectionUtils.isEmpty(formGroupFieldAddList)) {
                int fieldSort = 1;
                for (FormGroupFieldAddDTO field : formGroupFieldAddList) {
                    field.setSubjectId(saveFormGroup.getId() + "");
                    field.setSort(fieldSort++);
                    field.setModuleName(formGroupAdd.getModuleName());
                    this.addFieldCode(field);
                    bachSaveFieldList.add(field);
                }
            }
        }
        if (!CollectionUtils.isEmpty(bachSaveFieldList)) {
            formGroupFieldService.batchSave(bachSaveFieldList, tokenUser);
        }
        // 最后修改流程的parentId
        long childSort = 1;
        if (!CollectionUtils.isEmpty(processChildList) && !ObjectUtils.isEmpty(processId)) {
            for (FormGroupDO formGroupDO : processChildList) {
                formGroupDO.setParentId(processId);
                formGroupDO.setSort(childSort++);
                formGroupDO.setLevel(2);
                formGroupService.updateByIdSelective(formGroupDO);
            }
        }
        return template.to(TreatmentDisposeTemplateVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(TreatmentDisposeTemplateUpdateDTO updateDTO, TokenUser tokenUser) {
        //转DO
        TreatmentDisposeTemplateDO treatmentDisposeTemplateDO = updateDTO.to(TreatmentDisposeTemplateDO.class);
        // 校验名称
        checkTemplateName(updateDTO.getTemplateName(), updateDTO.getId(), tokenUser);
        // 拿到表单
        List<FormGroupUpdateDTO> formGroupList = updateDTO.getFormGroupUpdateList();
        // 校验字段名称全模板不可重复
        checkFieldName(null, formGroupList);
        // 拿到原有的的所有处理流程
        List<FormGroupVO> existingProcessChildList = formGroupService.selectBySubjectIdAndFormType(updateDTO.getId(),
                FormGroupModuleCode.DYCL, FormGroupModuleCode.PROCESS_CHILD, tokenUser);
        Map<Long, FormGroupVO> existingProcessChildMap = existingProcessChildList
                .stream().collect(Collectors.toMap(FormGroupVO::getId, v -> v));
        List<FormGroupUpdateDTO> processChildAddList = new ArrayList<>();
        List<FormGroupUpdateDTO> processChildUpdateList = new ArrayList<>();
        List<Long> updateProcessIdList = new ArrayList<>();
        List<FormGroupFieldAddDTO> bachSaveFieldList = new ArrayList<>();
        List<Long> deleteFieldIdList = new ArrayList<>();
        Long process = null;
        for (FormGroupUpdateDTO formGroupUpdateDTO : formGroupList) {
            // 表单分为 三大部分 员工个人信息,事件概况,和处理过程  处理过程下 有 子流程
            // 员工个人信息,事件概况,处理过程  不可变  所以直接处理表单内字段,子流程可编辑 可删除拿出去做单独处理
            if (FormGroupModuleCode.PROCESS_CHILD.equals(formGroupUpdateDTO.getModuleCode())) {
                if (StringUtils.isEmpty(formGroupUpdateDTO.getId())) {
                    processChildAddList.add(formGroupUpdateDTO);
                } else {
                    processChildUpdateList.add(formGroupUpdateDTO);
                    updateProcessIdList.add(formGroupUpdateDTO.getId());
                }
                continue;
            }
            if (FormGroupModuleCode.PROCESS.equals(formGroupUpdateDTO.getModuleCode())) {
                process = formGroupUpdateDTO.getId();
                continue;
            }
            // 处理表单内字段
            unifiedEditing(formGroupUpdateDTO, bachSaveFieldList, deleteFieldIdList, tokenUser);
        }
        if (!CollectionUtils.isEmpty(processChildAddList)) {
            // 新增的处理流程, 新增的处理流程内的字段一定都是新增
            for (FormGroupUpdateDTO addProcessChild : processChildAddList) {
                List<FormGroupFieldDYCLUpdateDTO> fieldList = addProcessChild.getFormGroupFieldUpdateList();
                FormGroupDO formGroup = addProcessChild.to(FormGroupDO.class);
                formGroup.setSubjectId(updateDTO.getId());
                formGroup.setParentId(process);
                FormGroupDO saveGroup = formGroupService.save(formGroup, tokenUser.getSiteId(), tokenUser.getUserId());
                if (!CollectionUtils.isEmpty(fieldList)) {
                    bachSaveFieldList.addAll(fieldList.stream().map(field -> {
                        FormGroupFieldAddDTO toResult = field.to(FormGroupFieldAddDTO.class);
                        toResult.setSubjectId(saveGroup.getId() + "");
                        return toResult;
                    }).collect(Collectors.toList()));
                }
            }
        }
        if (!CollectionUtils.isEmpty(processChildUpdateList)) {
            // 修改的处理流程,这里需要再来一套上面的  新增的 修改的  删除的
            // 处理流程是可以修改名称的,如果名称改了 还得先把这个流程更新一下
            for (FormGroupUpdateDTO formGroupUpdate : processChildUpdateList) {
                FormGroupVO formGroup = existingProcessChildMap.get(formGroupUpdate.getId());
                if (!formGroup.getModuleName().equals(formGroupUpdate.getModuleName())) {
                    formGroupService.update(formGroupUpdate, tokenUser);
                }
                // 处理表单内字段
                unifiedEditing(formGroupUpdate, bachSaveFieldList, deleteFieldIdList, tokenUser);
            }
        }
        for (FormGroupVO existingProcessChild : existingProcessChildList) {
            if (!updateProcessIdList.contains(existingProcessChild.getId())) {
                formGroupService.deleteByIds(tokenUser, true, existingProcessChild.getId());
            }
        }
        if (!CollectionUtils.isEmpty(bachSaveFieldList)) {
            List<FormGroupFieldVO> addFieldResult = formGroupFieldService.batchSave(bachSaveFieldList, tokenUser);
            // 用这个模板的事件同步新增一下这些字段
            treatmentDisposeEventService.addFieldAsyncUpdateEvent(updateDTO.getId(), addFieldResult, tokenUser);
        }
        if (!CollectionUtils.isEmpty(deleteFieldIdList)) {
            Long[] deleteIdArray = new Long[deleteFieldIdList.size()];
            deleteFieldIdList.toArray(deleteIdArray);
            formGroupFieldService.deleteByIds(tokenUser, true, deleteIdArray);
        }
        //根据主键更新，只更新非null值
        return updateByIdSelective(treatmentDisposeTemplateDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... treatmentDisposeTemplateIds) {
        List<String> updateFinishEventIdList = new ArrayList<>();
        // 查询这些模板下的未完结事件
        for (String templateId : treatmentDisposeTemplateIds) {
            List<TreatmentDisposeEventDO> eventList = treatmentDisposeEventService
                    .selectNotFinishEventByTemplateId(templateId, tokenUser);
            if (!CollectionUtils.isEmpty(eventList)) {
                updateFinishEventIdList.addAll(eventList.stream()
                        .map(TreatmentDisposeEventDO::getId).collect(Collectors.toList()));
            }
        }
        // 把未完结的事件全部改为已完结
        if (!CollectionUtils.isEmpty(updateFinishEventIdList)) {
            treatmentDisposeEventService.bachUpdateFinish(updateFinishEventIdList);
        }
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) treatmentDisposeTemplateIds);
    }


    @Override
    public TreatmentDisposeTemplateVO selectById(String treatmentDisposeTemplateId, String siteId) {
        TreatmentDisposeTemplateDO treatmentDisposeTemplateDO = selectDOById(treatmentDisposeTemplateId, siteId);
        if (treatmentDisposeTemplateDO == null) {
            return null;
        }
        return treatmentDisposeTemplateDO.to(TreatmentDisposeTemplateVO.class);
    }

    @Override
    public List<TreatmentDisposeTemplateListVO> select(TreatmentDisposeTemplateQuery treatmentDisposeTemplateQuery, String siteId) {
        List<TreatmentDisposeTemplateDO> treatmentDisposeTemplateDOList = selectDO(treatmentDisposeTemplateQuery, siteId);
        if (CollectionUtils.isEmpty(treatmentDisposeTemplateDOList)) {
            return treatmentDisposeTemplateDOList == null ? null : new ArrayList<>();
        }
        return treatmentDisposeTemplateDOList.stream()
                .map(treatmentDisposeTemplateDO -> treatmentDisposeTemplateDO.to(TreatmentDisposeTemplateListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(TreatmentDisposeTemplateQuery treatmentDisposeTemplateQuery, String siteId) {
        Example example = buildExample(treatmentDisposeTemplateQuery, siteId);
        return treatmentDisposeTemplateDAO.selectCountByExample(example);
    }

    @Override
    public Page<TreatmentDisposeTemplateListVO> selectPage(TreatmentDisposeTemplateQuery treatmentDisposeTemplateQuery, String siteId) {
        Example example = buildExample(treatmentDisposeTemplateQuery, siteId);
        Page<TreatmentDisposeTemplateDO> page = treatmentDisposeTemplateDAO.selectPageByExample(example,
                treatmentDisposeTemplateQuery.getPageNo(),
                treatmentDisposeTemplateQuery.getPageSize());

        return page.to(TreatmentDisposeTemplateListVO.class);
    }

    @Override
    public TreatmentDisposeTemplateDO selectDOById(String treatmentDisposeTemplateId, String siteId) {
        return listById(treatmentDisposeTemplateId, siteId);
    }

    @Override
    public List<TreatmentDisposeTemplateDO> selectDO(TreatmentDisposeTemplateQuery treatmentDisposeTemplateQuery, String siteId) {
        Example example = buildExample(treatmentDisposeTemplateQuery, siteId);
        return treatmentDisposeTemplateDAO.selectByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<TreatmentDisposeTemplateVO> selectSiteDefaultTemplate(TokenUser tokenUser) {
        // 先查询当前登录用户租户的默认模板
        Example example = new Example(TreatmentDisposeTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("templateType", "system")
                .andEqualTo("siteId", tokenUser.getSiteId());
        // 为了防止两个人同时点击导致创建两遍默认模板
        synchronized (this) {
            List<TreatmentDisposeTemplateDO> siteTemplateList = treatmentDisposeTemplateDAO.selectByExample(example);
            // 如果租户下没有默认模板,就去找系统默认的默认模板copy一份放在租户下
            if (CollectionUtils.isEmpty(siteTemplateList)) {
                // 初始化默认模板
                initSiteDefaultTemplate(tokenUser);
                siteTemplateList = treatmentDisposeTemplateDAO.selectByExample(example);
            }
            List<String> modifiedUserIdList = siteTemplateList.stream()
                    .map(TreatmentDisposeTemplateDO::getModifiedUserId).collect(Collectors.toList());
            Map<String, UserDO> userMap = buildUserMap(modifiedUserIdList);
            return siteTemplateList.stream().map(template -> {
                TreatmentDisposeTemplateVO toResult = template.to(TreatmentDisposeTemplateVO.class);
                if ("system".equals(toResult.getModifiedUserId())) {
                    toResult.setModifiedUserName("系统默认");
                } else {
                    UserDO user = userMap.get(toResult.getModifiedUserId());
                    if (!ObjectUtils.isEmpty(user)) {
                        toResult.setModifiedUserName(user.getName());
                    }
                }
                return toResult;
            }).collect(Collectors.toList());
        }
    }

    @Override
    public Page<TreatmentDisposeTemplateVO> selectCustomTemplatePage(
            TreatmentDisposeTemplateQuery templateQuery, TokenUser tokenUser) {
        Example example = new Example(TreatmentDisposeTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("templateType", "custom")
                .andEqualTo("siteId", tokenUser.getSiteId());
        if (!StringUtils.isEmpty(templateQuery.getTemplateName())) {
            example.and().andLike("templateName", "%" + templateQuery.getTemplateName() + "%");
        }
        List<TreatmentDisposeTemplateDO> selectTemplateList = treatmentDisposeTemplateDAO.selectByExample(example);
        List<TreatmentDisposeTemplateVO> resultList = selectTemplateList.stream()
                .map(template -> template.to(TreatmentDisposeTemplateVO.class)).collect(Collectors.toList());
        // 赋值编辑人
        List<String> modifiedUserIdList = resultList.stream()
                .map(TreatmentDisposeTemplateVO::getModifiedUserId).collect(Collectors.toList());
        Map<String, UserDO> userMap = buildUserMap(modifiedUserIdList);
        resultList = resultList.stream().peek(template -> {
            UserDO user = userMap.get(template.getModifiedUserId());
            if (!ObjectUtils.isEmpty(user)) {
                template.setModifiedUserName(user.getName());
            }
        }).filter(template -> {
            if (!StringUtils.isEmpty(templateQuery.getModifiedUserName())) {
                return template.getModifiedUserName().contains(templateQuery.getModifiedUserName());
            } else {
                return true;
            }
        }).collect(Collectors.toList());
        return PageKit.startPage(resultList, templateQuery.getPageNo(), templateQuery.getPageSize());
    }

    @Override
    public List<TreatmentDisposeTemplateDO> selectAllTemplateBySite(String name, TokenUser tokenUser) {
        // 先查询当前登录用户租户的默认模板
        Example example = new Example(TreatmentDisposeTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("templateType", "system")
                .andEqualTo("siteId", tokenUser.getSiteId());
        List<TreatmentDisposeTemplateDO> siteTemplateList = treatmentDisposeTemplateDAO.selectByExample(example);
        // 如果租户下没有默认模板,就去找系统默认的默认模板copy一份放在租户下
        if (CollectionUtils.isEmpty(siteTemplateList)) {
            // 初始化默认模板
            initSiteDefaultTemplate(tokenUser);
        }
        example.clear();
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        if (!StringUtils.isEmpty(name)) {
            example.and().andLike("templateName", "%" + name + "%");
        }
        return treatmentDisposeTemplateDAO.selectByExample(example);
    }

    @Override
    public TreatmentDisposeTemplateVO selectTemplateInfoById(String templateId, TokenUser tokenUser) {
        TreatmentDisposeTemplateDO template = this.selectDOById(templateId, tokenUser.getSiteId());
        if (ObjectUtils.isEmpty(template)) {
            throw new ParamException("模板不存在或已删除");
        }
        TreatmentDisposeTemplateVO result = template.to(TreatmentDisposeTemplateVO.class);
        List<FormGroupVO> formGroupList = this.selectFormGroupByTemplateId(result.getId(), null, tokenUser);
        result.setFormGroupTree(formGroupList);
        return result;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void bachSave(List<TreatmentDisposeTemplateDO> insertList) {
        treatmentDisposeTemplateDAO.insertListAndSetId(insertList);
    }

    @Override
    public List<TreatmentDisposeTemplateDO> selectSystemDefaultTemplate() {
        Example example = new Example(TreatmentDisposeTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("templateType", "system")
                .andEqualTo("siteId", "system");
        example.orderBy("templateName");
        return treatmentDisposeTemplateDAO.selectByExample(example);
    }

    @Override
    public String generateExcel(String templateId, TokenUser tokenUser) {
        TreatmentDisposeTemplateDO template = selectDOById(templateId, tokenUser.getSiteId());
        if (ObjectUtils.isEmpty(template)) {
            throw new ParamException("模板不存在或已删除");
        }
        List<List<String>> headList = new ArrayList<>();
        // 这三个表头是固定的
        List<String> fixedHeadList = Arrays.asList("接单时间", "接单客服", "所属用工单位");
        for (String head : fixedHeadList) {
            List<String> fixedHead = new ArrayList<>();
            fixedHead.add(head);
            headList.add(fixedHead);
        }
        List<FormGroupVO> formGroupList = formGroupService
                .selectBySubjectIdAndFormType(template.getId(), FormGroupModuleCode.DYCL, null, tokenUser);
        List<String> formGroupIdList = formGroupList.stream()
                .map(formGroup -> formGroup.getId() + "").collect(Collectors.toList());
        // 以表单做分组
        Map<String, List<FormGroupFieldDO>> formGroupFieldMap = groupTemplateField(formGroupIdList, "site");
        // 指定标红的坐标
        List<ExcelAxisDTO> redAxisList = new ArrayList<>();
        redAxisList.add(new ExcelAxisDTO(0, 0));
        redAxisList.add(new ExcelAxisDTO(0, 1));
        redAxisList.add(new ExcelAxisDTO(0, 2));
        redAxisList.add(new ExcelAxisDTO(1, 3));
        redAxisList.add(new ExcelAxisDTO(1, 4));
        // 指定批注坐标及内容
        List<ExcelAxisDTO> annotationList = new ArrayList<>();
        annotationList.add(new ExcelAxisDTO(0, 0, "接单时间：格式为YYYY-MM-DD；"));
        annotationList.add(new ExcelAxisDTO(0, 1, "接单客服：需与系统内已创建的账号 姓名相同"));
        annotationList.add(new ExcelAxisDTO(0, 2, "所属用工单位：需与系统内已创建的用工单位名称相同"));
        annotationList.add(new ExcelAxisDTO(1, 3, "姓名：该列为必填项"));
        annotationList.add(new ExcelAxisDTO(1, 4, "港澳居民来往内地通行证号码、台湾居民来往大陆通行证号码"));
        // 指定下拉框
        List<ExcelAxisDTO> dropDownList = new ArrayList<>();
        int index = 3;
        for (FormGroupVO formGroup : formGroupList) {
            List<FormGroupFieldDO> formGroupFieldList = formGroupFieldMap.get(formGroup.getId() + "");
            if (!CollectionUtils.isEmpty(formGroupFieldList)) {
                formGroupFieldList = formGroupFieldList.stream()
                        .filter(field -> field.getFieldType() != 7).collect(Collectors.toList());
                for (FormGroupFieldDO formGroupField : formGroupFieldList) {
                    List<String> head = new ArrayList<>();
                    int rowIndex = 2;
                    if (FormGroupModuleCode.PROCESS_CHILD.equals(formGroup.getModuleCode())) {
                        head.add("处理过程");
                    }
                    head.add(formGroup.getModuleName());
                    head.add(formGroupField.getFieldName());
                    headList.add(head);
                    if (FieldType.DROP_DOWN.getValue().equals(formGroupField.getFieldType()) &&
                            !StringUtils.isEmpty(formGroupField.getOptions())) {
                        String[] dropDown = formGroupField.getOptions().split(",");
                        dropDownList.add(new ExcelAxisDTO(rowIndex, index, dropDown));
                    }
                    index++;
                }
            }
        }
        // 批注和下拉框
        GenerateExcelHead generateExcelHead = new GenerateExcelHead(redAxisList, annotationList, dropDownList);
        return ExcelKit.generateExcel("模板", headList, "模板", new ArrayList<>(), null, generateExcelHead);
    }

    @Override
    public List<FormGroupVO> selectFormGroupByTemplateId(String templateId, String eventId, TokenUser tokenUser) {
        // 查询对应模板下的所有表单
        List<FormGroupVO> formGroupList = formGroupService
                .selectBySubjectIdAndFormType(templateId, FormGroupModuleCode.DYCL, null, tokenUser);
        for (FormGroupVO formGroupVO : formGroupList) {
            // 查询对应表单下的所有字段
            List<FormGroupFieldVO> formGroupFieldList;
            // 事件Id为空说明只查询字段不查询字段里的内容,eventId不为空说明查询的是某个事件下地字段需要把字段里面的内容也查询出来
            if (StringUtils.isEmpty(eventId)) {
                List<FormGroupFieldDO> fieldList = formGroupFieldService
                        .selectBySubjectIdList(Collections.singletonList(formGroupVO.getId() + ""), "site");
                formGroupFieldList = fieldList.stream()
                        .map(formGroupField -> {
                            FormGroupFieldVO toResult = formGroupField.to(FormGroupFieldVO.class);
                            // 后端如果 Content 为空,返回前端,则是一个,null 导致前端显示一个hull,现在前端不再做处理,所以这里需要吧为空的全部改为空串
                            if (StringUtils.isEmpty(toResult.getContent())) {
                                toResult.setContent("");
                            }
                            return toResult;
                        }).collect(Collectors.toList());
                formGroupVO.setFormGroupFieldList(formGroupFieldList);
            } else {
                FormGroupFieldQuery query = new FormGroupFieldQuery();
                query.setSubjectIdList(Collections.singletonList(formGroupVO.getId()));
                query.setEventId(eventId);
                formGroupFieldList = formGroupFieldService.selectFieldAddContentByQuery(query, tokenUser);
                for (FormGroupFieldVO formGroupField : formGroupFieldList) {
                    // 后端如果 Content 为空,返回前端,则是一个,null 导致前端显示一个hull,现在前端不再做处理,所以这里需要吧为空的全部改为空串
                    if (StringUtils.isEmpty(formGroupField.getContent())) {
                        formGroupField.setContent("");
                    }
                }
                formGroupVO.setFormGroupFieldList(formGroupFieldList);
            }
        }
        // 把表单变为树形结构,因为[处理过程设置]表单下还有一级[流程] 所以要做成树形结构
        // 不过这里已经固定了只有[处理过程设置]表单下有二级表单并且只有一级所以这里就写死了,以后若有需求可以在这里调用通用方法改造组织树
        // 有必要时可以根据DepInfo类重写此方法:  FormGroupService buildFormGroupTree();
        // 把moduleCode为processChild的都找出来,如果不为空则List中的元素必为[处理过程设置]中的二级表单
        List<FormGroupVO> processChild = formGroupList.stream()
                .filter(formGroup -> FormGroupModuleCode.PROCESS_CHILD.equals(formGroup.getModuleCode()))
                .sorted(Comparator.comparing(FormGroupVO::getSort))
                .collect(Collectors.toList());
        // 把二级表单过滤掉,并且把[处理过程设置]的二级表单设置进去
        return formGroupList.stream()
                .filter(formGroup -> !FormGroupModuleCode.PROCESS_CHILD.equals(formGroup.getModuleCode()))
                .peek(formGroup -> {
                    // 如果是[处理过程设置]就把上面的二级表单设置进来
                    if (FormGroupModuleCode.PROCESS.equals(formGroup.getModuleCode())) {
                        formGroup.setChildList(processChild);
                    }
                }).collect(Collectors.toList());
    }

    @Override
    public List<FormGroupFieldDO> selectFieldByTemplateId(String templateId, TokenUser tokenUser) {
        List<FormGroupFieldDO> result = new ArrayList<>();
        // 查询对应模板下的所有表单
        List<FormGroupVO> formGroupList = formGroupService
                .selectBySubjectIdAndFormType(templateId, FormGroupModuleCode.DYCL, null, tokenUser);
        for (FormGroupVO formGroupVO : formGroupList) {
            // 查询对应表单下的所有字段
            List<FormGroupFieldDO> formGroupFieldList = formGroupFieldService
                    .selectBySubjectIdList(Collections.singletonList(formGroupVO.getId() + ""), "site");
            result.addAll(formGroupFieldList);
        }
        return result;
    }

    @Override
    public List<FormGroupVO> selectProcessChildByTemplateId(String templateId, TokenUser tokenUser) {
        return formGroupService.selectBySubjectIdAndFormType(templateId,
                FormGroupModuleCode.DYCL, FormGroupModuleCode.PROCESS_CHILD, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void copyTemplate(String templateId, TokenUser tokenUser) {
        TreatmentDisposeTemplateDO sourceTemplate = selectDOById(templateId, tokenUser.getSiteId());
        String sourceTemplateId = sourceTemplate.getId();
        // 先生成一下目标模板的名字
        String resultName = this.copyTemplateGenerateName(sourceTemplate.getTemplateName(), 1, tokenUser);
        sourceTemplate.setTemplateName(resultName);
        // 不管是不是系统模板 copy 出来都是自定义模板
        sourceTemplate.setTemplateType("custom");
        sourceTemplate.setId(null);
        // 保存目标模板
        TreatmentDisposeTemplateDO targetTemplate = save(sourceTemplate, tokenUser.getSiteId(), tokenUser.getUserId());
        List<FormGroupVO> sourceFormGroupList = formGroupService
                .selectBySubjectIdAndFormType(sourceTemplateId, FormGroupModuleCode.DYCL, null, tokenUser);
        // 把源模板的表单搞一份存到目标模板
        String processId = null;
        List<FormGroupDO> processChildList = new ArrayList<>();
        for (FormGroupVO formGroup : sourceFormGroupList) {
            String sourceFormGroupId = formGroup.getId() + "";
            FormGroupDO sourceFormGroup = formGroup.to(FormGroupDO.class);
            sourceFormGroup.setId(null);
            sourceFormGroup.setSubjectId(targetTemplate.getId());
            FormGroupDO targetForGroup = formGroupService
                    .save(sourceFormGroup, tokenUser.getSiteId(), tokenUser.getUserId());
            if (FormGroupModuleCode.PROCESS.equals(targetForGroup.getModuleCode())) {
                processId = targetForGroup.getId() + "";
            }
            if (FormGroupModuleCode.PROCESS_CHILD.equals(targetForGroup.getModuleCode())) {
                processChildList.add(targetForGroup);
            }
            // 查询源表单下的字段
            List<FormGroupFieldDO> sourceFieldList = formGroupFieldService
                    .selectBySubjectIdList(Collections.singletonList(sourceFormGroupId), "site");
            for (FormGroupFieldDO sourceField : sourceFieldList) {
                sourceField.setId(null);
                sourceField.setSubjectId(targetForGroup.getId() + "");
                formGroupFieldService.save(sourceField, tokenUser.getSiteId(), tokenUser.getUserId());
            }
        }
        if (!CollectionUtils.isEmpty(processChildList) && !ObjectUtils.isEmpty(processId)) {
            for (FormGroupDO formGroupDO : processChildList) {
                formGroupDO.setParentId(Long.parseLong(processId));
                formGroupDO.setLevel(2);
                formGroupService.updateByIdSelective(formGroupDO);
            }
        }
    }

    /**
     * 初始化租户的四个默认模板
     */
    private void initSiteDefaultTemplate(TokenUser tokenUser) {
        // 查询系统提供的默认模板
        List<TreatmentDisposeTemplateDO> systemTemplateList = this.selectSystemDefaultTemplate();
        for (TreatmentDisposeTemplateDO template : systemTemplateList) {
            String systemDefaultId = template.getId();
            template.setId(null);
            template.preInsert(tokenUser.getUserId());
            template.setSiteId(tokenUser.getSiteId());
            template.setModifiedUserId("system");
            template.setGmtCreate(new Date());
            TreatmentDisposeTemplateDO saveResult = save(template);
            // 初始化此模板的表单和字段,因为页面只显示模板信息所以这里使用多线程
            initDefaultFormByTemplate(saveResult, systemDefaultId, tokenUser);
        }
    }

    /**
     * 根据默认模板初,始化模板下的所有表单和字段
     */
    @Async
    public void initDefaultFormByTemplate(TreatmentDisposeTemplateDO saveResult,
                                          String systemDefaultId, TokenUser tokenUser) {
        List<FormGroupFieldDO> formGroupFieldInsertList = new ArrayList<>();
        // 查询对应默认模板的所有表单
        List<FormGroupVO> formGroupVOList = formGroupService
                .selectBySubjectIdAndFormType(systemDefaultId, FormGroupModuleCode.DYCL, null, tokenUser);
        List<FormGroupDO> formGroupList = formGroupVOList.stream()
                .map(formGroup -> formGroup.to(FormGroupDO.class)).collect(Collectors.toList());
        List<String> formGroupIdList = formGroupList.stream()
                .map(formGroup -> formGroup.getId() + "").collect(Collectors.toList());
        // 以表单做分组
        Map<String, List<FormGroupFieldDO>> formGroupFieldMap = groupTemplateField(formGroupIdList, "system");
        Long processId = null;
        List<FormGroupDO> processChildList = new ArrayList<>();
        // 把默认表单copy一份保存到对应租户下
        for (FormGroupDO formGroup : formGroupList) {
            // 拿到这个表单分组下的所有字段
            List<FormGroupFieldDO> formGroupFieldList = formGroupFieldMap.get(formGroup.getId() + "");
            formGroup.setId(null);
            formGroup.setSubjectId(saveResult.getId());
            formGroup.setSubjectType("site");
            formGroup.setSiteId(tokenUser.getSiteId());
            formGroup.preInsert(tokenUser.getUserId());
            // 保存表单
            FormGroupDO personalInfoForm = formGroupService
                    .save(formGroup, tokenUser.getSiteId(), tokenUser.getUserId());
            if (FormGroupModuleCode.PROCESS.equals(formGroup.getModuleCode())) {
                processId = personalInfoForm.getId();
            }
            if (FormGroupModuleCode.PROCESS_CHILD.equals(formGroup.getModuleCode())) {
                processChildList.add(personalInfoForm);
            }
            if (!CollectionUtils.isEmpty(formGroupFieldList)) {
                for (FormGroupFieldDO formGroupField : formGroupFieldList) {
                    formGroupField.setSiteId(tokenUser.getSiteId());
                    formGroupField.setId(null);
                    formGroupField.setSubjectType("site");
                    formGroupField.setSiteId(tokenUser.getSiteId());
                    formGroupField.preInsert(tokenUser.getUserId());
                    formGroupField.setSubjectId(personalInfoForm.getId() + "");
                    formGroupFieldInsertList.add(formGroupField);
                }
            }
            // 把流程的父级Id改一下
            if (!ObjectUtils.isEmpty(processId) && !CollectionUtils.isEmpty(processChildList)) {
                for (FormGroupDO formGroupUpdate : processChildList) {
                    formGroupUpdate.setParentId(processId);
                    formGroupService.updateByIdSelective(formGroupUpdate);
                }
            }
        }
        formGroupFieldService.batchSaveDO(formGroupFieldInsertList);
    }

    /**
     * 校验模板名称是否重复
     */
    private void checkTemplateName(String template, String templateId, TokenUser tokenUser) {
        if (StringUtils.isEmpty(template)) {
            throw new ParamException("模板名称不能为空");
        }
        Example example = new Example(TreatmentDisposeTemplateDO.class);
        example.and()
                .andEqualTo("templateName", template)
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        if (!StringUtils.isEmpty(templateId)) {
            example.and().andNotEqualTo("id", templateId);
        }
        List<TreatmentDisposeTemplateDO> templateList = treatmentDisposeTemplateDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(templateList)) {
            throw new ParamException("已存在同名模板，不可创建");
        }
    }

    /**
     * 校验字段名称
     */
    private void checkFieldName(TreatmentDisposeTemplateAddDTO checkSource) {
        List<FormGroupAddDTO> formGroupList = checkSource.getFormGroupAddList();
        List<String> checkList = new ArrayList<>();
        for (FormGroupAddDTO formGroup : formGroupList) {
            List<FormGroupFieldAddDTO> fieldList = formGroup.getFormGroupFieldAddList();
            if (!CollectionUtils.isEmpty(fieldList)) {
                for (FormGroupFieldAddDTO field : fieldList) {
                    if (checkList.contains(field.getFieldName())) {
                        throw new ParamException("[" + field.getFieldName() + "]" + "字段名称重复");
                    }
                    checkList.add(field.getFieldName());
                }
            }
        }
    }

    /**
     * 根据表单Id查询表单下的所有字段,以表单做分组返回
     */
    private Map<String, List<FormGroupFieldDO>> groupTemplateField(List<String> formGroupIdList, String subjectType) {
        // 查询模板下所有字段
        List<FormGroupFieldDO> templateFieldList = formGroupFieldService
                .selectBySubjectIdList(formGroupIdList, subjectType);
        // 以表单做分组
        return templateFieldList.stream().collect(Collectors.groupingBy(FormGroupFieldDO::getSubjectId));
    }


    /**
     * 编辑模板时统一处理表单内新增字段 修改字段 和 删除字段
     */
    private void unifiedEditing(FormGroupUpdateDTO formGroupUpdateDTO, List<FormGroupFieldAddDTO> bachSaveFieldList,
                                List<Long> deleteFieldIdList, TokenUser tokenUser) {
        // 查询原有的 表单内字段
        List<FormGroupFieldDO> existingFieldList = formGroupFieldService
                .selectBySubjectIdList(Collections.singletonList(formGroupUpdateDTO.getId() + ""), "site");
        List<Long> existingFieldIdList = existingFieldList.stream()
                .map(FormGroupFieldDO::getId).collect(Collectors.toList());
        // 拿到  编辑后的  表单字段
        List<FormGroupFieldDYCLUpdateDTO> formGroupFieldUpdate = formGroupUpdateDTO.getFormGroupFieldUpdateList();
        if (!CollectionUtils.isEmpty(formGroupFieldUpdate)) {
            List<Long> updateFieldIdList = formGroupFieldUpdate.stream()
                    .map(FormGroupFieldDYCLUpdateDTO::getId)
                    .filter(fieldId -> !ObjectUtils.isEmpty(fieldId))
                    .collect(Collectors.toList());
            // 没有Id的则是新增  有Id的是修改 对比之前的表单内字段 消失了的需要删除
            List<FormGroupFieldDYCLUpdateDTO> addUpdateList = formGroupFieldUpdate.stream()
                    .filter(field -> StringUtils.isEmpty(field.getId())).collect(Collectors.toList());
            // 新增的
            if (!CollectionUtils.isEmpty(addUpdateList)) {
                bachSaveFieldList.addAll(addUpdateList.stream().map(field -> {
                    FormGroupFieldAddDTO toResult = field.to(FormGroupFieldAddDTO.class);
                    toResult.setSubjectId(formGroupUpdateDTO.getId() + "");
                    return toResult;
                }).collect(Collectors.toList()));
            }
            // 修改的
            List<FormGroupFieldDYCLUpdateDTO> updateList = formGroupFieldUpdate.stream()
                    .filter(field -> !StringUtils.isEmpty(field.getId())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(updateList)) {
                for (FormGroupFieldDYCLUpdateDTO updateFieldDTO : updateList) {
                    formGroupFieldService.update(updateFieldDTO.to(FormGroupFieldUpdateDTO.class), tokenUser);
                }
            }
            // 删除的
            for (Long fieldId : existingFieldIdList) {
                if (!updateFieldIdList.contains(fieldId)) {
                    deleteFieldIdList.add(fieldId);
                }
            }

        }
    }

    /**
     * [更新] 或者 [新增] 模板时校验所有 [字段] 和[ 处理流程] 在 [全模板内不可重复]
     */
    private void checkFieldName(List<FormGroupAddDTO> formGroupAddList, List<FormGroupUpdateDTO> formGroupUpdateList) {
        // 两个List同一时间只会传一个进来
        List<String> checkNameList = new ArrayList<>();
        List<String> checkProcessNameList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(formGroupAddList)) {
            List<String> processChildNameList = formGroupAddList.stream()
                    .filter(add -> FormGroupModuleCode.PROCESS_CHILD.equals(add.getModuleCode()))
                    .map(FormGroupAddDTO::getModuleName).collect(Collectors.toList());
            for (FormGroupAddDTO formGroupAdd : formGroupAddList) {
                List<FormGroupFieldAddDTO> addFieldList = formGroupAdd.getFormGroupFieldAddList();
                if (!CollectionUtils.isEmpty(addFieldList)) {
                    for (FormGroupFieldAddDTO addField : addFieldList) {
                        if (checkNameList.contains(addField.getFieldName())) {
                            throw new ParamException("字段名为[" + addField.getFieldName() + "]的字段重复");
                        }
                        if (processChildNameList.contains(addField.getFieldName())) {
                            throw new ParamException("字段名为[" + addField.getFieldName() + "]的字段与流程名称重复");
                        }
                        checkNameList.add(addField.getFieldName());
                    }
                }
                if (FormGroupModuleCode.PROCESS_CHILD.equals(formGroupAdd.getModuleCode())) {
                    if (checkProcessNameList.contains(formGroupAdd.getModuleName())) {
                        throw new ParamException("流程名为[" + formGroupAdd.getModuleName() + "]的流程重复");
                    }
                    if (CollectionUtils.isEmpty(formGroupAdd.getFormGroupFieldAddList())) {
                        throw new ParamException("流程名为[" + formGroupAdd.getModuleName() + "]的流程下字段为空");
                    }
                    checkProcessNameList.add(formGroupAdd.getModuleName());
                }
            }
        }
        if (!CollectionUtils.isEmpty(formGroupUpdateList)) {
            List<String> processChildNameList = formGroupUpdateList.stream()
                    .filter(add -> FormGroupModuleCode.PROCESS_CHILD.equals(add.getModuleCode()))
                    .map(FormGroupUpdateDTO::getModuleName).collect(Collectors.toList());
            for (FormGroupUpdateDTO formGroupUpdate : formGroupUpdateList) {
                List<FormGroupFieldDYCLUpdateDTO> updateFieldList = formGroupUpdate.getFormGroupFieldUpdateList();
                if (!CollectionUtils.isEmpty(updateFieldList)) {
                    for (FormGroupFieldDYCLUpdateDTO updateField : updateFieldList) {
                        if (checkNameList.contains(updateField.getFieldName())) {
                            throw new ParamException("字段名为[" + updateField.getFieldName() + "]的字段重复");
                        }
                        if (processChildNameList.contains(updateField.getFieldName())) {
                            throw new ParamException("字段名为[" + updateField.getFieldName() + "]的字段与流程名称重复");
                        }
                        checkNameList.add(updateField.getFieldName());
                    }
                }
                if (FormGroupModuleCode.PROCESS_CHILD.equals(formGroupUpdate.getModuleCode())) {
                    if (checkProcessNameList.contains(formGroupUpdate.getModuleName())) {
                        throw new ParamException("流程名为[" + formGroupUpdate.getModuleName() + "]的流程重复");
                    }
                    if (CollectionUtils.isEmpty(formGroupUpdate.getFormGroupFieldUpdateList())) {
                        throw new ParamException("流程名为[" + formGroupUpdate.getModuleName() + "]的流程下字段为空");
                    }
                    checkProcessNameList.add(formGroupUpdate.getModuleName());
                }
            }
        }
    }

    /**
     * 新增模板时   [姓名],[性别],[手机号],[身份证号] 这四个需要单独设置fieldCode
     */
    private void addFieldCode(FormGroupFieldAddDTO field) {
        String fieldName = field.getFieldName();
        switch (fieldName) {
            case "姓名":
                field.setFieldCode("name");
                break;
            case "性别":
                field.setFieldCode("sex");
                break;
            case "手机号":
                field.setFieldCode("phone");
                break;
            case "身份证号":
                field.setFieldCode("idCard");
                break;
            case "工作地点":
                field.setFieldCode("workCity");
                break;
        }
    }

    /**
     * 构建一个UserMap
     */
    private Map<String, UserDO> buildUserMap(List<String> modifiedUserIdList) {
        List<UserDO> userList = userProviderService.selectUserByIds(modifiedUserIdList);
        return userList.stream().collect(Collectors.toMap(UserDO::getId, v -> v));
    }

    /**
     * copy模板生成模板名称
     */
    private String copyTemplateGenerateName(String sourceTemplateName, int index, TokenUser tokenUser) {
        Example example = new Example(TreatmentDisposeTemplateDO.class);
        example.and()
                .andEqualTo("templateName", sourceTemplateName + "(" + index + ")")
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        List<TreatmentDisposeTemplateDO> template = treatmentDisposeTemplateDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(template)) {
            index = index + 1;
            return copyTemplateGenerateName(sourceTemplateName, index, tokenUser);
        } else {
            return sourceTemplateName + "(" + index + ")";
        }
    }

    /**
     * 根据查询参数，构建example
     *
     * @param treatmentDisposeTemplateQuery 查询参数
     * @param siteId                        所属站点id
     * @return example
     */
    private Example buildExample(TreatmentDisposeTemplateQuery treatmentDisposeTemplateQuery, String siteId) {
        Example example = new Example(TreatmentDisposeTemplateDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        // 排序
        ExampleKit.setExampleOrder(example, treatmentDisposeTemplateQuery.getOrders());
        return example;
    }
}




